--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 26944da12754b8663ba4bd99dfb50e254864ab78
Parents : 93fde98
Author : Mark Qvist <mark@unsigned.io>
Date : 2025-11-27T14:16:21+01:00
Fixed darwin import
Changes
2 files changed, 186 insertions(+), 1 deletions(-)
Diff
diff --git a/LXST/Platforms/darwin/coreaudioconstants.py b/LXST/Platforms/darwin/coreaudioconstants.py
new file mode 100644
index 0000000..5cdef04
--- /dev/null
+++ b/LXST/Platforms/darwin/coreaudioconstants.py
@@ -0,0 +1,185 @@
+# Adapted from Bastian Bechtold's soundcard library, originally released
+# under the BSD 3-Clause License
+#
+# https://github.com/bastibe/SoundCard
+#
+# Copyright (c) 2016 Bastian Bechtold
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the
+# distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Modifications and improvements Copyright 2025 Mark Qvist, and released
+# under the same BSD 3-Clause License.
+
+kAudioObjectSystemObject = 1
+kAudioHardwarePropertyDevices = int.from_bytes(b'dev#', byteorder='big')
+kAudioHardwarePropertyDefaultInputDevice = int.from_bytes(b'dIn ', byteorder='big')
+kAudioHardwarePropertyDefaultOutputDevice = int.from_bytes(b'dOut', byteorder='big')
+
+kAudioObjectPropertyScopeGlobal = int.from_bytes(b'glob', byteorder='big')
+kAudioObjectPropertyScopeInput = int.from_bytes(b'inpt', byteorder='big')
+kAudioObjectPropertyScopeOutput = int.from_bytes(b'outp', byteorder='big')
+kAudioObjectPropertyScopePlayThrough = int.from_bytes(b'ptru', byteorder='big')
+
+kAudioObjectPropertyName = int.from_bytes(b'lnam', byteorder='big')
+kAudioObjectPropertyModelName = int.from_bytes(b'lmod', byteorder='big')
+kAudioObjectPropertyManufacturer = int.from_bytes(b'lmak', byteorder='big')
+
+kAudioDevicePropertyNominalSampleRate = int.from_bytes(b'nsrt', byteorder='big')
+kAudioDevicePropertyBufferFrameSize = int.from_bytes(b'fsiz', byteorder='big')
+kAudioDevicePropertyBufferFrameSizeRange = int.from_bytes(b'fsz#', byteorder='big')
+kAudioDevicePropertyUsesVariableBufferFrameSizes = int.from_bytes(b'vfsz', byteorder='big')
+kAudioDevicePropertyStreamConfiguration = int.from_bytes(b'slay', byteorder='big')
+
+kCFStringEncodingUTF8 = 0x08000100
+kAudioObjectPropertyElementMaster = 0
+
+kAudioUnitType_Output = int.from_bytes(b'auou', byteorder='big')
+kAudioUnitManufacturer_Apple = int.from_bytes(b'appl', byteorder='big')
+kAudioUnitSubType_GenericOutput = int.from_bytes(b'genr', byteorder='big')
+kAudioUnitSubType_HALOutput = int.from_bytes(b'ahal', byteorder='big')
+kAudioUnitSubType_DefaultOutput = int.from_bytes(b'def ', byteorder='big')
+# The audio unit can do input from the device as well as output to the
+# device. Bus 0 is used for the output side, bus 1 is used to get audio
+# input from the device.
+outputbus = 0
+inputbus = 1
+
+def error_number_to_string(num):
+ if num == kAudioUnitErr_InvalidProperty:
+ return "The property is not supported"
+ elif num == kAudioUnitErr_InvalidParameter:
+ return "The parameter is not supported"
+ elif num == kAudioUnitErr_InvalidElement:
+ return "The specified element is not valid"
+ elif num == kAudioUnitErr_NoConnection:
+ return "There is no connection (generally an audio unit is asked to render but it has" \
+ " not input from which to gather data)"
+ elif num == kAudioUnitErr_FailedInitialization:
+ return "The audio unit is unable to be initialized"
+ elif num == kAudioUnitErr_TooManyFramesToProcess:
+ return "When an audio unit is initialized it has a value which specifies the max" \
+ " number of frames it will be asked to render at any given time. If an audio" \
+ " unit is asked to render more than this, this error is returned."
+ elif num == kAudioUnitErr_InvalidFile:
+ return "If an audio unit uses external files as a data source, this error is returned" \
+ " if a file is invalid (Apple's DLS synth returns this error)"
+ elif num == kAudioUnitErr_UnknownFileType:
+ return "If an audio unit uses external files as a data source, this error is returned" \
+ " if a file is invalid (Apple's DLS synth returns this error)"
+ elif num == kAudioUnitErr_FileNotSpecified:
+ return "If an audio unit uses external files as a data source, this error is returned" \
+ " if a file hasn't been set on it (Apple's DLS synth returns this error)"
+ elif num == kAudioUnitErr_FormatNotSupported:
+ return "Returned if an input or output format is not supported"
+ elif num == kAudioUnitErr_Uninitialized:
+ return "Returned if an operation requires an audio unit to be initialized and it is not."
+ elif num == kAudioUnitErr_InvalidScope:
+ return "The specified scope is invalid"
+ elif num == kAudioUnitErr_PropertyNotWritable:
+ return "The property cannot be written"
+ elif num == kAudioUnitErr_CannotDoInCurrentContext:
+ return "Returned when an audio unit is in a state where it can't perform the requested" \
+ " action now - but it could later. Its usually used to guard a render operation" \
+ " when a reconfiguration of its internal state is being performed."
+ elif num == kAudioUnitErr_InvalidPropertyValue:
+ return "The property is valid, but the value of the property being provided is not"
+ elif num == kAudioUnitErr_PropertyNotInUse:
+ return "Returned when a property is valid, but it hasn't been set to a valid value at this time."
+ elif num == kAudioUnitErr_Initialized:
+ return "Indicates the operation cannot be performed because the audio unit is initialized."
+ elif num == kAudioUnitErr_InvalidOfflineRender:
+ return "Used to indicate that the offline render operation is invalid. For instance," \
+ " when the audio unit needs to be pre-flighted, but it hasn't been."
+ elif num == kAudioUnitErr_Unauthorized:
+ return "Returned by either Open or Initialize, this error is used to indicate that the" \
+ " audio unit is not authorised, that it cannot be used. A host can then present" \
+ " a UI to notify the user the audio unit is not able to be used in its current state."
+ elif num == kAudioComponentErr_InstanceInvalidated:
+ return "the component instance's implementation is not available, most likely because the process" \
+ " that published it is no longer running"
+ else:
+ return "error number {}".format(num)
+
+kAudioUnitErr_InvalidProperty = -10879
+kAudioUnitErr_InvalidParameter = -10878
+kAudioUnitErr_InvalidElement = -10877
+kAudioUnitErr_NoConnection = -10876
+kAudioUnitErr_FailedInitialization = -10875
+kAudioUnitErr_TooManyFramesToProcess = -10874
+kAudioUnitErr_InvalidFile = -10871
+kAudioUnitErr_UnknownFileType = -10870
+kAudioUnitErr_FileNotSpecified = -10869
+kAudioUnitErr_FormatNotSupported = -10868
+kAudioUnitErr_Uninitialized = -10867
+kAudioUnitErr_InvalidScope = -10866
+kAudioUnitErr_PropertyNotWritable = -10865
+kAudioUnitErr_CannotDoInCurrentContext = -10863
+kAudioUnitErr_InvalidPropertyValue = -10851
+kAudioUnitErr_PropertyNotInUse = -10850
+kAudioUnitErr_Initialized = -10849
+kAudioUnitErr_InvalidOfflineRender = -10848
+kAudioUnitErr_Unauthorized = -10847
+kAudioComponentErr_InstanceInvalidated = -66749
+kAudioUnitErr_RenderTimeout = -66745
+
+kAudioOutputUnitProperty_CurrentDevice = 2000
+kAudioOutputUnitProperty_EnableIO = 2003 # scope output, element 0 == output,
+kAudioOutputUnitProperty_HasIO = 2006 # scope input, element 1 == input
+kAudioOutputUnitProperty_IsRunning = 2001
+kAudioOutputUnitProperty_ChannelMap = 2002
+
+kAudioFormatLinearPCM = int.from_bytes(b'lpcm', byteorder='big')
+kAudioFormatFlagIsFloat = 0x1
+
+kAudioUnitProperty_StreamFormat = 8
+kAudioUnitProperty_CPULoad = 6
+kAudioUnitProperty_Latency = 12
+kAudioUnitProperty_SupportedNumChannels = 13
+kAudioUnitProperty_MaximumFramesPerSlice = 14
+kAudioUnitProperty_SetRenderCallback = 23
+kAudioOutputUnitProperty_SetInputCallback = 2005
+kAudioUnitProperty_StreamFormat = 8
+kAudioUnitProperty_SampleRate = 2
+kAudioUnitProperty_ContextName = 25
+kAudioUnitProperty_ElementName = 30
+kAudioUnitProperty_NickName = 54
+
+kAudioUnitRenderAction_PreRender = 1 << 2
+kAudioUnitRenderAction_PostRender = 1 << 3
+kAudioUnitRenderAction_OutputIsSilence = 1 << 4
+kAudioOfflineUnitRenderAction_Preflight = 1 << 5
+kAudioOfflineUnitRenderAction_Render = 1 << 6
+kAudioOfflineUnitRenderAction_Complete = 1 << 7
+kAudioUnitRenderAction_PostRenderError = 1 << 8
+kAudioUnitRenderAction_DoNotCheckRenderArgs = 1 << 9
+
+kAudioUnitScope_Global = 0 # The context for audio unit characteristics that apply to the audio unit as a whole
+kAudioUnitScope_Input = 1 # The context for audio data coming into an audio unit
+kAudioUnitScope_Output = 2 # The context for audio data leaving an audio unit
\ No newline at end of file
diff --git a/LXST/Platforms/darwin/soundcard.py b/LXST/Platforms/darwin/soundcard.py
index a9ed662..100ae10 100644
--- a/LXST/Platforms/darwin/soundcard.py
+++ b/LXST/Platforms/darwin/soundcard.py
@@ -55,7 +55,7 @@ with open(os.path.join(_package_dir, 'coreaudio.h'), 'rt') as f:
_ca = _ffi.dlopen('CoreAudio')
_au = _ffi.dlopen('AudioUnit')
-from soundcard import coreaudioconstants as _cac
+import LXST.Platforms.darwin.coreaudioconstants as _cac
def all_speakers():
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────